#define _CRT_SECURE_NO_WARNINGS 1

/**
* C++11
*/

#include <iostream>
#include <vector>
#include <array>
#include <forward_list>
#include <unordered_map>
#include <unordered_set>
#include <algorithm>
#include <map>
#include <stack>
#include <string>
using namespace std;
#include "string.h"

struct Point
{
	int _x;
	int _y;
};

double func(double a, double b)
{
	return a + b;
}

int func(int a)
{
	return a;
}

//函数模板 万能引用，给左值，是左值引用，给右值，是右值引用
template<class T>
void perfectForward(T&& t)
{
	func(forward<T>(t)); //forward<T>保持t的左右属性
}

int main1()
{
	//1.列表初始化

	//C风格 数组，结构体
	int	arr1[] = { 1,2,3 };
	Point p = { 1,2 };

	//扩展 基本类型，=省略
	int i = 0;
	int j = { 0 };
	int k{ 0 };
	int	arr2[]{ 1,2,3 };
	Point p1{ 1,2 }; //列表初始化

	Point p2 = { 1,2 }; //多参构造隐式类型转换，参数个数要匹配，不匹配识别成initializer_list

	//列表初始化器 initializer_list
	//对于STL容器，先构造成initializer_list，再调用initializer_list版本的构造函数
	//对于自定义容器，只要支持initializer_list构造，即可支持列表初始化
	vector<int> v1 = { 1,2,3 };


	//2.推导类型
	int type1 = 1;
	double type2 = 1.2;

	//typeid().name() 拿到类型的字符串
	cout << typeid(type1).name() << endl;
	cout << typeid(type2).name() << endl;

	//decltype 拿到类型关键字
	auto to_decl = type1 * type2;
	decltype(to_decl) decl; //定义变量
	vector<decltype(to_decl)> vec_decl; //作模板参数


	//3.新容器
	array<int, 10> arr3; //检查越界
	forward_list<int> list; //节省空间
	unordered_map<int, int> map;
	unordered_set<int> set;


	//4.右值引用

	//引用 -> 减少拷贝

	//左值：可以取地址，可以修改
	int left1 = 0;
	int* left2 = new int(0);
	const int left3 = 10; //常量（常性变量）
	void push_back(int&& x); //右值x被右值引用引用后是左值

	//左值引用
	int& ref1 = left1;
	int*& ref2 = left2;
	int& ref_p2 = *left2;
	const int& ref3 = left3;

	double a = 1.2, b = 2.3;
	//右值：不能取地址，不能修改
	10; //字面常量
	a + b; //表达式返回值
	func(a, b); //传值返回

	//右值引用
	int&& rref1 = 10;
	double&& rref2 = a + b;
	double&& rref3 = func(a, b);

	//左值引用引用右值 - 加const保持权限
	const int& rright = 10;

	//右值引用引用左值 - move()
	int&& rleft = move(a); //move返回值是右值，a还是左值

	//5.默认成员函数

	//增加 默认移动构造 和 默认移动赋值
	//当未实现 移动构造 拷贝构造 赋值重载 析构 时生成默认移动构造，内置类型浅拷贝，自定义类型调移动构造，没有的调拷贝构造
	//默认移动赋值同理

	//string(string&& s) = default; //强制生成默认成员函数
	//string(string&& s) = delete; //禁止生成默认成员函数


	return 0;
}



//6.可变参数模板

//参数包为空，换行，结束递归
void _showList()
{
	cout << endl;
}

//编译时递归推演，参数包不为空，val为第一个，agrs为剩下的
template<class T, class ...Args>
void _showList(const T& val, Args... args)
{
	cout << val << " ";
	_showList(args...);
}

//Args模板参数包 args形参参数包
//...在args左侧（...args），表示这是参数包
//...在args右侧（args...），表示将参数包逐项展开
template<class ...Args>
void showList(Args... args)
{
	//cout << sizeof...(args) << endl; //求参数包中的参数数量
	_showList(args...); //打印参数包所有参数
}

int main2()
{
	showList(1);
	showList(1, 2.2);
	showList(1, 2.2, 'a');
	showList(1, 2.2, 'a', "abc");

	return 0;
}


int main3()
{
	//7.lambda表达式

	//[捕获列表](形参列表) mutable去常性 -> 返回值类型 {函数体};
	auto lambda1 = [](int x) -> int {
		cout << x << endl;
		return 0;
	}; //底层是仿函数

	lambda1(10); //lambda1是函数对象
	cout << typeid(lambda1).name() << endl; // class <lambda_856c49ef8d96d34c9903652de2ea1e84>

	vector<Point> vecp = { {1, 2}, {2, 3}, {3, 4} };
	sort(vecp.begin(), vecp.end(), [](const Point& p1, const Point& p2) -> int {
		return p1._x > p2._x;
	});

	//捕获：不用传参，直接用所在域中的变量
	//
	//[变量]传值捕获
	//[&变量]引用捕获
	//[=]传值捕获所有变量
	//[&]引用捕获所有变量
	//[this]捕获this指针

	int x = 10, y = 20;
	auto lambda2 = [&x, &y]() mutable -> void {
		int tmp = x;
		x = y;
		y = tmp;
	}; //捕获变量 x y 加mutable表示可修改

	return 0;
}



//8.包装器function 特殊的类模板

// 包装器 -> 包装可调用对象 -> 函数指针，仿函数，lambda -> 用法统一
// 函数指针 -> 写法反人类
// 仿函数 -> 用法过重
// lambda -> 类型匿名

#include <functional>

void func_swap(int& x, int& y)
{
	int tmp = x;
	x = y;
	y = tmp;
}

struct class_swap
{
	void operator()(int& x, int& y)
	{
		int tmp = x;
		x = y;
		y = tmp;
	}
};

int main4()
{
	int x = 10, y = 20;

	auto lambda_swap = [](int& x, int& y) -> void {
		int tmp = x;
		x = y;
		y = tmp;
	};

	//返回值是void，参数是两个int&的方法 的包装器
	function<void(int& x, int& y)> function1 = func_swap;//函数指针
	function<void(int& x, int& y)> function2 = class_swap();//仿函数
	function<void(int& x, int& y)> function3 = lambda_swap;//lambda

	function3(x, y); //交换x y

	return 0;
}

//逆波兰表达式求值，优雅
class Plus {
public:
	int evalRPN(vector<string>& tokens) {
		stack<int> sta;
		map<string, function<int(int, int)>> options = {
			{"+", [](int x, int y) { return x + y; }},
			{"-", [](int x, int y) { return x - y; }},
			{"*", [](int x, int y) { return x * y; }},
			{"/", [](int x, int y) { return x / y; }}
		};
		for (auto a : tokens) {
			if (options.count(a)) {
				int right = sta.top();
				sta.pop();

				int left = sta.top();
				sta.pop();

				sta.push(options[a](left, right));
			}
			else {
				int i = stoi(a);
				sta.push(i);
			}
		}
		return sta.top();
	}
};

class PlusXY
{
public:
	static int plus1(int x, int y)
	{
		return x + y;
	}

	int plus2(int x, int y)
	{
		return x + y;
	}
};

int main5()
{	
	//包装（静态）成员函数指针：取地址类域::函数名
	function<int(int, int)> f1 = &PlusXY::plus1; 
	function<int(PlusXY*, int, int)> f2 = &PlusXY::plus2; //成员函数有this指针

	PlusXY p;
	cout << f2(&p, 10, 20) << endl;

	return 0;
}